﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ValidationEngine.Commons;

namespace ValidationEngine.Core
{
    /// <summary>
    /// IValidatorsMgr implementation
    /// </summary>
    internal class ValidatorsMgr : IValidatorsMgr
    {
        #region Members
        private Dictionary<Type, IValidator> _validators = new Dictionary<Type, IValidator>(); 
        #endregion

        #region IValidatorsMgr
        /// <summary>
        /// Scans model's type namespace for sub namespace Validators and try to find there IValidator for the model
        /// </summary>
        /// <param name="modelType">Model type</param>
        public void FindAndRegisterValidatorForType(Type modelType)
        {
            if (_validators.ContainsKey(modelType))
            {
                return;
            }
            Assembly ai = modelType.Assembly;
            var namespaceName = modelType.FullName.Substring(0, modelType.FullName.Length - modelType.Name.Length - 1);
            var validatorsNamespace = namespaceName + ".Validators";
            Type validatorType = ai.GetTypes().Where(t => t.Namespace != null && t.Namespace.Equals(validatorsNamespace) && t.Name.Equals(modelType.Name + "Validator")).FirstOrDefault();
            if (null != validatorType)
            {
                RegisterValidator(modelType, (IValidator)Activator.CreateInstance(validatorType));
            }
        }

        /// <summary>
        /// Adds not added yet validator for model type
        /// </summary>
        /// <param name="modelType">Model type</param>
        /// <param name="validator">Validator instance</param>
        public void RegisterValidator(Type modelType, IValidator validator)
        {
            if (null != validator && !_validators.ContainsKey(modelType))
            {
                _validators.Add(modelType, validator);
            }
        }

        /// <summary>
        /// Checks if validator registered for model type
        /// </summary>
        /// <param name="modelType">Model type</param>
        /// <param name="validator">Validator instance</param>
        /// <returns></returns>
        public bool IsValidatorRegistered(Type modelType, IValidator validator)
        {
            IValidator registeredValidator;
            _validators.TryGetValue(modelType, out registeredValidator);
            return validator != null && registeredValidator == validator;
        }

        /// <summary>
        /// Returns validator for model type
        /// </summary>
        /// <param name="modelType">Model type</param>
        /// <returns>Validator instance if registered</returns>
        public IValidator GetValidatorForType(Type modelType)
        {
            IValidator validator;
            _validators.TryGetValue(modelType, out validator);
            return validator;
        } 
        #endregion
    }
}
